package com.woniuxy.service.impl;

import com.alibaba.fastjson.JSON;
import com.woniuxy.entity.Book;
import com.woniuxy.entity.KillBook;
import com.woniuxy.entity.KillOrder;
import com.woniuxy.producer.DelayProducer;
import com.woniuxy.producer.TopicProducer;
import com.woniuxy.service.SecKillService;
import com.woniuxy.util.*;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author ：CuiYC
 * @description：
 * @date ：Created in 2025/3/18 14:24
 * @modified By：
 */
@Service
@AllArgsConstructor
public class SecKillServiceImpl implements SecKillService {


    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private DelayProducer delayProducer;
    /**
     * 添加秒杀书籍
     *      1：写入到秒杀表中
     *      2：写入到redis中
     * @param killBook
     * @return
     */
    @Override
    public ResponseData<?> addKillBook(KillBook killBook) {
        //要求：无论什么时候点击秒杀书籍，书籍信息只会提前五分钟进入redis秒杀书籍表
        /**
         * 前端：可隐藏的秒杀开始时间提示块
         * 后端：
         *      书籍上线方法放入延迟队列
         *      请求秒杀书籍
         */
        //1：写入到秒杀表中

        //2：写入到redis中
        /**
         * 计算TTL时间
         */
        String startTime = killBook.getStartTime();
        LocalDateTime localDateTime = MyDateTimeUtil.StringToLocalDataTime(startTime);

        // 计算两个时间点之间的差异。从当前时间到指定时间点，计算差异。老的在后。
        localDateTime = localDateTime.minusMinutes(5);//提前五分钟
        Duration duration = Duration.between(LocalDateTime.now(), localDateTime);

        // 将差异转换为毫秒
        Integer diffInMilliSeconds = (int)duration.toMillis();

        String jsonString = JSON.toJSONString(killBook);
        delayProducer.send(jsonString, "showKillBook", diffInMilliSeconds);
        return ResponseData.ok();
    }

    /**
     * 查询秒杀书籍
     * @return
     */
    @Override
    public ResponseData<?> queryKillBook() {
        List<Object> killBook = redisTemplate.opsForHash().values("SECKILLSERVICEIMPL:ADDKILLBOOK");
        return ResponseData.ok(killBook);
    }

    /**
     * 查询秒杀书籍详情
     * @param bookId
     * @return
     */
    @Override
    public ResponseData<?> queryDetail(Integer bookId) {
        KillBook killBook = (KillBook)redisTemplate.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK", bookId + "");
        return ResponseData.ok(killBook);
    }

    /**
     * 用户抢购接口
     *      1：判断库存是否足够
     *          不够：返回
     *      2：减库存
     *      3：生成秒杀订单
     */
    @Autowired
    private TopicProducer topicProducer;
    @Override
    public synchronized ResponseData<?> startKill(Integer bookId) {
        //跟线程加标识
        String uuid = UUID.randomUUID().toString();//当前线程中保存了该标识
        try {
            //setIfAbsent()就是封装了setnx指令
            Boolean b = redisTemplate.opsForValue().setIfAbsent("lock", uuid);
            KillBook killBook = null;
            if(b){
                //1：判断库存是否足够
                killBook = (KillBook)redisTemplate.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK", bookId + "");
                if (killBook.getKillNum() < 1) {
                    //库存不足
                    return ResponseData.fail(ResponseEnum.Kill_END);
                }
                //2：减库存
                killBook.setKillNum(killBook.getKillNum()-1);
                System.out.println("剩余库存:"+killBook.getKillNum());
                redisTemplate.opsForHash().put("SECKILLSERVICEIMPL:ADDKILLBOOK",bookId+"",killBook);
            }else {
                //没有获取到锁
                return ResponseData.fail(ResponseEnum.Kill_END);
            }


            //3：生成秒杀订单（不能直接写入MySql而是改用RabbitMq异步写入）
            KillOrder killOrder = new KillOrder();
            SnowflakeIdGenerator snowflakeIdGenerator = new SnowflakeIdGenerator();
            long l = snowflakeIdGenerator.nextId();
            killOrder.setKillOrderNum(String.valueOf(l));
            killOrder.setBookId(bookId);
            Integer userId = UserContext.getUserId();
            killOrder.setUserId(userId);
            killOrder.setPrice(killBook.getDiscountPrice());
            killOrder.setKillNum(1);
            killOrder.setStatus("1");
            String jsonString = JSON.toJSONString(killOrder);
            //把订单编号存入redis
            redisTemplate.opsForValue().set("killOrderNum:"+killOrder.getKillOrderNum(),killOrder.getKillOrderNum(), 5, TimeUnit.MINUTES);


            topicProducer.send(jsonString, "killBook");

            return ResponseData.ok();

        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            //仅删除当前线程自己的锁
            if(uuid.equals(redisTemplate.opsForValue().get("lock"))){
                //释放锁 删除锁标识
                redisTemplate.delete("lock");
            }
        }
    }
}
